import numpy as np
import tensorflow as tf

# ②	使用minimize计算一元二次方程的最小值
# 1)	创建一个无参有返回值的函数，用于返回创建的一元二次方程，a=1,b=-4,c=2
x = tf.Variable(0., dtype=tf.float32, name='x')
a = tf.constant(1., dtype=tf.float32, name='a')
b = tf.constant(-4., dtype=tf.float32, name='b')
c = tf.constant(2., dtype=tf.float32, name='c')


@tf.function
def xmodel():
    y = a * x ** 2 + b * x + c
    return y


# 3)	使用minimize计算一元二次方程的最小值
@tf.function
def xstep():
    opt.minimize(xmodel, [x])
    y = xmodel()
    return y


# 2)	使用随机梯度下降，自行选择学习率和循环次数
alpha = 0.01
iters = 400
opt = tf.keras.optimizers.SGD(learning_rate=alpha)
group = int(np.ceil(iters / 10))
x_last = x.numpy()
for i in range(iters):
    y = xstep()
    x_this = x.numpy()
    if np.isclose(x_last, x_this):
        print('Converged!')
        break
    x_last = x_this
    if i % group == 0:
        print(f'#{i + 1}: x = {x_this}, y = {y}')
if i % group != 0:
    print(f'#{i + 1}: x = {x_this}, y = {y}')

# 4)	输出该一元二次方程的最小值及对应的x值
print(f'该一元二次方程的最小值: {y}, 及对应的x值: {x_this}')
x.assign(- b / (2 * a))
y = xmodel()
print(f'该一元二次方程的理论最小值: {y.numpy()}, 及对应的x值: {x.numpy()}')
